package org.codehaus.mojo.wagon;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.wagon.CommandExecutor;
import org.apache.maven.wagon.Streams;
import org.apache.maven.wagon.Wagon;
import org.apache.maven.wagon.WagonException;
import org.apache.maven.wagon.providers.ssh.jsch.AbstractJschWagon;

/**
 * Executes a list of commands against a given server.
 */
@Mojo(name = "sshexec")
public class SshExecMojo extends AbstractSingleWagonMojo {

    private static final String TAIL_F = "tail -f";

    /**
     * The commands that we will execute.
     */
    @Parameter(required = true)
    private String[] commands;

    /**
     * Allow option not to fail the build on error.
     */
    @Parameter(defaultValue = "true")
    private boolean failOnError = true;

    /**
     * Option to display remote command's outputs.
     */
    @Parameter(defaultValue = "false")
    private boolean displayCommandOutputs = true;

    @Override
    protected void execute(final Wagon wagon) throws MojoExecutionException {
        if (commands != null) {
            for (String command : commands) {
                if (command.startsWith(TAIL_F)) {
                    executeTailF(wagon, command);
                } else {
                    executeItem(wagon, command, false);
                }
            }
        }
    }

    private void executeTailF(Wagon wagon, String command) {
        this.getLog().info("sshexec: " + command + " ...");
        String substring = command.substring(TAIL_F.length());
        int line = 1;
        int sum = 0;
        while (true) {
            String cmd = "sed -n '" + line + "," + line + "p' " + substring;
            try {
                int ret = executeItem(wagon, cmd, true);
                sum = ret + sum;
                if (sum > 20) {
                    break;
                }
                try {
                    Thread.sleep(250L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ret != 1) {
                    sum = 0;
                }
            } catch (MojoExecutionException e) {
                e.printStackTrace();
            }
            line = line + 1;
        }
    }

    private int executeItem(final Wagon wagon, String command, boolean notLog) throws MojoExecutionException {
        try {
            Streams stream;
            if (wagon instanceof AbstractJschWagon) {
                stream = ((AbstractJschWagon) wagon).executeCommand(command, true, false);
            } else {
                stream = ((CommandExecutor) wagon).executeCommand(command, false);
            }
            if (!notLog) {
                this.getLog().info("sshexec: " + command + " ...");
            }
            if (displayCommandOutputs) {
                String out = stream.getOut();
                String err = stream.getErr();
                if (isNotEmpty(out) || isNotEmpty(err)) {
                    print(out);
                    print(err);
                    return 0;
                } else {
                    return 1;
                }
            }
            return 0;
        } catch (final WagonException e) {
            if (this.failOnError) {
                throw new MojoExecutionException("Unable to execute remote command", e);
            } else {
                this.getLog().warn(e);
            }
        }
        return 0;
    }

    private void print(String str) {
        if (isNotEmpty(str)) {
            System.out.println(str.replaceAll("\\r\\n|\\r|\\n", ""));
        }
    }

    private boolean isEmpty(String str) {
        if (str == null) {
            return true;
        }
        return str.trim().length() == 0;
    }

    private boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }
}
